package com.qigao.mall.web.controller.notify;

import com.qigao.mall.api.ChannelRouteService;
import com.qigao.mall.api.PayService;
import com.qigao.mall.api.RefundService;
import com.qigao.mall.channel.dto.ChannelRefundRespDto;
import com.qigao.mall.commons.dto.PayNotifyDto;
import com.qigao.mall.commons.enums.*;
import com.qigao.mall.commons.exceptions.BusinessException;
import com.qigao.mall.commons.utils.DateUtil;
import com.qigao.mall.commons.utils.PayUtil;
import com.qigao.mall.commons.utils.XMLUtil;
import com.qigao.mall.web.utils.RequestUtils;
import io.swagger.annotations.Api;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @author luiz
 * @Title: com.qigao.mall.web.controller.app
 * @ProjectName three-mall
 * @date 2019-11-2019/11/11 16:30
 * @Description:
 */
@RestController
@RequestMapping("/qigao/weichatNotify/")
@Api(tags = "App微信支付通知接口",value = "App微信支付通知接口")
public class WeiChatNotifyController {
    private static final Logger logger= LoggerFactory.getLogger(WeiChatNotifyController.class);
    @Resource
    private PayService payService;
    @Resource
    private RefundService refundService;
    @Resource
    ChannelRouteService channelRouteService;

    /**
     * 微信付款通知入口
     */
    @RequestMapping("pay")
    public String payNotify(HttpServletRequest request){
        String recvXml= RequestUtils.toString(request);
        logger.info("[微信付款通知]接受到的参数:{}",recvXml);
        Map retMap=new HashMap();
        retMap.put("return_code","SUCCESS");
        retMap.put("return_msg","OK");
        Map respMap= null;
        try{
            respMap = XMLUtil.doXMLParse(recvXml);
            //签名校验
            boolean compareFlag=channelRouteService.verifySign(respMap,WebSourceEnum.WEICHAT_JSAPI.getCode());
            if(!compareFlag){
                throw new BusinessException(ResultCode.SIGN_VALID_ERROR);
            }
            String retCode=(String) respMap.get("return_code");
            if(!"SUCCESS".equals(retCode)){
                logger.warn("【支付通知】通信标志失败,不做处理...");
                throw new BusinessException(ResultCode.CHANNEL_ERROR);
            }
            PayNotifyDto payNotifyDto=buildRespDto(respMap);
            payService.processNotifyOrder(payNotifyDto);
            logger.info("[微信付款通知]处理成功!");
        }catch (BusinessException be){
            retMap.put("return_code","FAIL");
            retMap.put("return_msg",be.getMsg());
            logger.error("[微信付款通知]处理发生业务异常:{}",be);
        }catch (JDOMException e) {
            retMap.put("return_code","FAIL");
            retMap.put("return_msg",e.getLocalizedMessage());
            logger.error("[微信付款通知]xml解析异常:{}",e);
        } catch (IOException e) {
            retMap.put("return_code","FAIL");
            retMap.put("return_msg",e.getLocalizedMessage());
            logger.error("[微信付款通知]xml解析IO异常:{}",e);
        }catch (Exception e){
            retMap.put("return_code","FAIL");
            retMap.put("return_msg","内部错误");
            logger.error("[微信付款通知]处理发生异常:{}",e);
        }
        String retXml= PayUtil.mapToXml(retMap);
        return retXml;
    }

    private PayNotifyDto buildRespDto(Map respMap) {
        PayNotifyDto payNotifyDto=new PayNotifyDto();
        payNotifyDto.setAppId((String) respMap.get("appId"));
        payNotifyDto.setMchId((String) respMap.get("mch_id"));
        payNotifyDto.setNonceStr((String) respMap.get("nonce_str"));
        payNotifyDto.setOpenid((String) respMap.get("openid"));
        payNotifyDto.setBuylerId((String) respMap.get("openid"));
        payNotifyDto.setIsSubscribe((String) respMap.get("is_subscribe"));
        payNotifyDto.setTradeType((String) respMap.get("trade_type"));
        payNotifyDto.setBankType((String) respMap.get("bank_type"));
        String totalFee=(String) respMap.get("total_fee");
        if(!StringUtils.isEmpty(totalFee)){
            payNotifyDto.setTotalFee(new BigDecimal(totalFee).divide(new BigDecimal(100)));
        }
        payNotifyDto.setTradeStatus(PayStatusEnum.PAY_SUCCESS);
        payNotifyDto.setCashFee((String) respMap.get("cash_fee"));
        payNotifyDto.setTransactionId((String) respMap.get("transaction_id"));
        payNotifyDto.setOutTradeNo((String) respMap.get("out_trade_no"));
        String timeEnd=(String) respMap.get("time_end");
        payNotifyDto.setTimeEnd(timeEnd);
        if(!StringUtils.isEmpty(timeEnd)){
            payNotifyDto.setPaySuccessTime(DateUtil.pareDate(timeEnd,"yyyyMMddHHmmss"));
        }
        return payNotifyDto;
    }

    @RequestMapping("refund")
    public String refundNotify(HttpServletRequest request){
        String recvXml= RequestUtils.toString(request);
        logger.info("[微信退款通知]接受到的参数:{}",recvXml);
        Map retMap=new HashMap();
        retMap.put("return_code","SUCCESS");
        retMap.put("return_msg","OK");
        Map<String,String> respMap= null;
        try{
            respMap = XMLUtil.doXMLParse(recvXml);
            //签名校验
            String refundNotifyData=channelRouteService.decryptData(respMap,WebSourceEnum.WEICHAT_JSAPI.getCode());
            if(StringUtils.isEmpty(refundNotifyData)){
                throw new BusinessException(ResultCode.SIGN_VALID_ERROR);
            }
            String retCode=(String) respMap.get("return_code");
            if(!"SUCCESS".equals(retCode)){
                logger.warn("【退款通知】通信标志失败,不做处理...");
                throw new BusinessException(ResultCode.CHANNEL_ERROR);
            }
            Map<String,String> refundDataMap = XMLUtil.doXMLParse(refundNotifyData);
            logger.info("【退款通知】退款数据:{}",refundDataMap);
            ChannelRefundRespDto channelRefundRespDto =buildRefundDto(refundDataMap);
            refundService.processNotifyOrder(channelRefundRespDto);
            logger.info("[微信退款通知]处理成功!");
        }catch (BusinessException be){
            retMap.put("return_code","FAIL");
            retMap.put("return_msg",be.getMsg());
            logger.error("[微信退款通知]处理发生业务异常:{}",be);
        }catch (JDOMException e) {
            retMap.put("return_code","FAIL");
            retMap.put("return_msg",e.getLocalizedMessage());
            logger.error("[退款通知]xml解析异常:{}",e);
        } catch (IOException e) {
            retMap.put("return_code","FAIL");
            retMap.put("return_msg",e.getLocalizedMessage());
            logger.error("[退款通知]xml解析IO异常:{}",e);
        }catch (Exception e){
            retMap.put("return_code","FAIL");
            retMap.put("return_msg","内部错误");
            logger.error("[微信退款通知]处理发生异常:{}",e);
        }
        String retXml= PayUtil.mapToXml(retMap);
        return retXml;
    }

    private ChannelRefundRespDto buildRefundDto(Map<String,String> refundDataMap) {
        ChannelRefundRespDto channelRefundRespDto =new ChannelRefundRespDto();
        channelRefundRespDto.setThirdTradeNo(refundDataMap.get("transaction_id"));
        channelRefundRespDto.setInnerSeqNo(refundDataMap.get("out_trade_no"));
        channelRefundRespDto.setThirdRefundNo(refundDataMap.get("refund_id"));
        channelRefundRespDto.setInnerRefundNo(refundDataMap.get("out_refund_no"));
        channelRefundRespDto.setIfSyn(YesNoEnum.NO);
        if(!StringUtils.isEmpty(refundDataMap.get("total_fee"))){
            BigDecimal refundAmt=new BigDecimal(refundDataMap.get("total_fee")).divide(new BigDecimal(100));
            channelRefundRespDto.setRefundAmt(refundAmt);
        }
        if("SUCCESS".equals(refundDataMap.get("refund_status"))){
            channelRefundRespDto.setRefundStatus(RefundStatusEnum.REFUND_SUCCESS);
        }else if("REFUNDCLOSE".equals(refundDataMap.get("refund_status"))){
            channelRefundRespDto.setRefundStatus(RefundStatusEnum.REFUND_CLOSE);
        }else if("CHANGE".equals(refundDataMap.get("refund_status"))) {
            channelRefundRespDto.setRefundStatus(RefundStatusEnum.REFUND_FAIL);
        }
       // tradeRefundRespDto.setRefundRecvAccount(refundDataMap.get("refund_recv_accout"));
       // tradeRefundRespDto.setRefundAccount(refundDataMap.get("refund_account"));
       // tradeRefundRespDto.setRefundRequestSource(refundDataMap.get("refund_request_source"));
        channelRefundRespDto.setRefundSuccessDate(DateUtil.pareDate(refundDataMap.get("success_time"),"yyyy-MM-dd HH:mm:ss"));
        return channelRefundRespDto;
    }

}
